#include <gtest/gtest.h>
#include "PCASolver.h"

#include <iostream>

class PCASolverTest : public ::testing::Test {

protected:

    bool isMatrixsEquals(const Eigen::MatrixXd * m1, Eigen::MatrixXd * m2) {
        if (m1->cols() != m2->cols() || m1->rows() != m2->rows()) {
            return false;
        }
        for (int j=0; j<m1->cols(); ++j) {
            for (int i=0; i<m2->rows(); ++i) {
                if ((fabs((*m1)(i,j)) - fabs((*m2)(i,j))) > 0.001) {
                    std::cerr << "Error on position: " << i << "," << j << std::endl;
                    std::cerr << "Error values: " << (*m1)(i,j) << " - " << (*m2)(i,j) << std::endl;
                    return false;
                }
            }
        }
        return true;
    }

    virtual void setUp() {
    }

    virtual void tearDown() {
        delete pCASolver;
    }

    PCASolver *pCASolver;
};

TEST_F(PCASolverTest, SimplePCATest) {
    Eigen::MatrixXd * m = new Eigen::MatrixXd(3,3);
    *m << 1, 2, 3,
            4, 5, 6,
            7, 8, 9;
    Eigen::MatrixXd * pc = new Eigen::MatrixXd(3,3);
    *pc << 0.57735,         0, -0.816497,
            0.57735, -0.707107,  0.408248,
            0.57735,  0.707107,  0.408248;

    pCASolver = new PCASolver(m, NULL);
    Eigen::MatrixXd * outcomePC = pCASolver->getPCMatrix();
    ASSERT_TRUE(isMatrixsEquals(pc, outcomePC));
    delete m;
}

TEST_F(PCASolverTest, SimplePCAReduceTest) {
    Eigen::MatrixXd * m = new Eigen::MatrixXd(3,3);
    *m << 1, 2, 3,
            4, 5, 6,
            7, 8, 9;
    Eigen::MatrixXd * reduced = new Eigen::MatrixXd(3,2);
    *reduced << -1.73205,   0.00000,
                -0.00000,   0.00000,
                0.00000,   0.00000;

    pCASolver = new PCASolver(m, NULL);
    Eigen::MatrixXd * reducedMatrix = pCASolver->performDimensionReduction(m, 2);
    ASSERT_TRUE(isMatrixsEquals(reduced, reducedMatrix));
    delete m;
}

int main(int argc, char ** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
